#include "GAF_Graphics.h"
#include "GAF_Face.h"

namespace GAF
{
	NotRender Graphics::m_NothingRender;

	UINT Graphics::m_nID = 0;
	UINT Graphics::GetID()
	{
		if(m_nID == 71)
			return m_nID++;
		return m_nID++;
	}

	Graphics::Graphics()
	{
		static char _szGraphicsName[20];
		SYS_MEMSET(_szGraphicsName, 0, sizeof(_szGraphicsName));
		SYS_SPRINTF(_szGraphicsName, "G_%d", GetID());

		m_nGType                = GRAPHICS_UNKNOW;
		ATTRIB(GraphicsName)    = _szGraphicsName;
		ATTRIB(Visible)         = true;
		ATTRIB(Location)        = GAF_POINT_ORIGIN;
		ATTRIB(Through)         = THROUGH_NONE;
		ATTRIB(Size)            = GAF_SIZE_ZERO;
		ATTRIB(Anchor)          = 0;
		ATTRIB(Offset)    = GAF_POINT_ORIGIN;
		ATTRIB(Alpha)           = GAF_ALPHA_DEFAULT;
		ATTRIB(Angle)           = GAF_ANGLE_DEFAULT;
		ATTRIB(ZoomX)           = GAF_ZOOM_DEFAULT;
		ATTRIB(ZoomY)           = GAF_ZOOM_DEFAULT;
		m_pgGroup               = NULL;
		m_isIgnoreSize          = false;
		m_pRender               = &m_NothingRender;
	}

	Graphics::~Graphics()
	{
	}

	bool Graphics::OnPreRender(GAF_CGraphics* pGraphics)
	{
		if(m_pgGroup != NULL)
			return m_pgGroup->OnPreRender(this);

		return true;
	}

	void Graphics::SetGraphicsName(STD_STRING strGraphicsName)
	{
		if(ATTRIB(GraphicsName).substr(0, 2) == "G_")
			ATTRIB(GraphicsName) = strGraphicsName;
	}

	void Graphics::SetLocation(int nX, int nY)
	{
		ATTRIB(Location).Set(nX, nY);
	}

	void Graphics::SetLocation(float fX, float fY, Graphics* pgFrame)
	{
		int nWidth = 0;
		int nHeight = 0;

		if(pgFrame != NULL)
		{
			nWidth = pgFrame->GetSize_a().nWidth;
			nHeight = pgFrame->GetSize_a().nHeight;
		}
		else if(m_pgGroup != NULL)
		{
			nWidth = m_pgGroup->GetSize_a().nWidth;
			nHeight = m_pgGroup->GetSize_a().nHeight;
		}
		else
		{
// 			nWidth = THE_PLATFORM->GetScreenWidth();
// 			nHeight = THE_PLATFORM->GetScreenHeight();
		}

		ATTRIB(Location).Set((int)(nWidth * fX), (int)(nHeight * fY));
	}

	void Graphics::SetAnchor(int nX, int nY)
	{
		ATTRIB(Anchor) = 0;
		SetOffset(nX, nY);
	}

	void Graphics::SetAnchor(float fX, float fY)
	{
		ATTRIB(Anchor) = 0;
		SetOffset((int)(ATTRIB(Size).nWidth * fX), (int)(ATTRIB(Size).nHeight * fY));
	}

	void Graphics::SetOffset(int nX, int nY)
	{
		ATTRIB(Offset).nX = nX;
		ATTRIB(Offset).nY = nY;
	}

	void Graphics::SetSize(UINT nWidth, UINT nHeight)
	{
		ATTRIB(Size).Set(nWidth, nHeight);
	}

	void Graphics::SetZoom(double dZoom)
	{
		ATTRIB(ZoomX) = dZoom;
		ATTRIB(ZoomY) = dZoom;
	}

	void Graphics::SetZoomWidth(UINT nWidth)
	{
		ATTRIB(ZoomX) = double(nWidth) / double(ATTRIB(Size).nWidth);
	}

	void Graphics::SetZoomHeight(UINT nHeight)
	{
		ATTRIB(ZoomY) = double(nHeight) / double(ATTRIB(Size).nHeight);
	}

	void Graphics::SetRender(Renderable* pRender)
	{
		m_pRender = pRender;
	}

	double Graphics::GetZoom()
	{
		return (ATTRIB(ZoomX) + ATTRIB(ZoomY)) / 2;
	}

	bool Graphics::GetScreenVisible()
	{
		if(ATTRIB(Visible) && m_pgGroup != NULL)
			return m_pgGroup->GetScreenVisible();
		else
			return ATTRIB(Visible);
	}

	int Graphics::GetScreenPosX()
	{
		int _nLocaX = ATTRIB(Location).nX;
		_nLocaX = (int)AdjustAssociate(_nLocaX, m_AllAssociates[ATTRIB_LOCAX]);

		int _nGroupX = 0;
		double _dGroupZoomX = 1.0f;

		if(m_pgGroup != NULL)
		{
			_dGroupZoomX = m_pgGroup->GetScreenZoomX();

			_nGroupX = m_pgGroup->GetScreenPosX();
			_nGroupX += m_pgGroup->GetOffset_a().nX;

			if((m_pgGroup->GetAnchor_a() & ANCHOR_HMASK) == ANCHOR_LEFT) {}
			else if((m_pgGroup->GetAnchor_a() & ANCHOR_HMASK) == ANCHOR_HCENTER)
				_nGroupX -= m_pgGroup->GetScreenSizeW() >> 1;
			else if((m_pgGroup->GetAnchor_a() & ANCHOR_HMASK) == ANCHOR_RIGHT)
				_nGroupX -= m_pgGroup->GetScreenSizeW();
		}

		return (int)(_nLocaX * _dGroupZoomX) + _nGroupX;
	}

	int Graphics::GetScreenPosY()
	{
		int _nLocaY = ATTRIB(Location).nY;
		_nLocaY = (int)AdjustAssociate(_nLocaY, m_AllAssociates[ATTRIB_LOCAY]);

		int _nGroupY = 0;
		double _dGroupZoomY = 1.0f;

		if(m_pgGroup != NULL)
		{
			_dGroupZoomY = m_pgGroup->GetScreenZoomY();

			_nGroupY = m_pgGroup->GetScreenPosY();
			_nGroupY += m_pgGroup->GetOffset_a().nY;

			if((m_pgGroup->GetAnchor_a() & ANCHOR_VMASK) == ANCHOR_TOP) {}
			else if((m_pgGroup->GetAnchor_a() & ANCHOR_VMASK) == ANCHOR_VCENTER)
				_nGroupY -= m_pgGroup->GetScreenSizeH() >> 1;
			else if((m_pgGroup->GetAnchor_a() & ANCHOR_VMASK) == ANCHOR_BUTTON)
				_nGroupY -= m_pgGroup->GetScreenSizeH();
		}

		return (int)(_nLocaY * _dGroupZoomY) + _nGroupY;
	}

	BYTE Graphics::GetScreenAlpha()
	{
		BYTE _bAlpha = GetAlpha_a();
		_bAlpha = (BYTE)AdjustAssociate(_bAlpha, m_AllAssociates[ATTRIB_ALPHA]);

		if(m_pgGroup != NULL)
		{
			BYTE _bGroupAlpha = m_pgGroup->GetScreenAlpha();
			if(_bGroupAlpha < 255)
				_bAlpha = (_bAlpha * _bGroupAlpha) >> 8;
		}

		return _bAlpha;

// 		BYTE _bAlpha;
// 		if(GetAlpha_a() > 0 && m_pgGroup != NULL)
// 		{
// 			_bAlpha = m_pgGroup->GetScreenAlpha();
// 			if(_bAlpha == 255)
// 				return GetAlpha_a();
// 			else
// 				return (BYTE)((GetAlpha_a() * _bAlpha) >> 8);
// 		}
// 		else
// 			return GetAlpha_a();
	}

	double Graphics::GetScreenAngle()
	{
		double _dAngle = GetAngle_a();
		_dAngle = AdjustAssociate(_dAngle, m_AllAssociates[ATTRIB_ANGLE]);

		if(m_pgGroup != NULL)
			_dAngle = _dAngle + m_pgGroup->GetScreenAngle();

		return _dAngle;
	}

	double Graphics::GetScreenZoomX()
	{
		double _dZoomX = GetZoomX_a();
		double _dZoom = AdjustAssociate(1, m_AllAssociates[ATTRIB_ZOOM]);
		_dZoomX = AdjustAssociate(_dZoomX, m_AllAssociates[ATTRIB_ZOOMX]);
		_dZoomX *= _dZoom;

		if(m_pgGroup != NULL)
			_dZoomX = _dZoomX * m_pgGroup->GetScreenZoomX();

		return _dZoomX;
	}

	double Graphics::GetScreenZoomY()
	{
		double _dZoomY = GetZoomY_a();
		double _dZoom = AdjustAssociate(1, m_AllAssociates[ATTRIB_ZOOM]);
		_dZoomY = AdjustAssociate(_dZoomY, m_AllAssociates[ATTRIB_ZOOMY]);
		_dZoomY *= _dZoom;

		if(m_pgGroup != NULL)
			_dZoomY = _dZoomY * m_pgGroup->GetScreenZoomY();

		return _dZoomY;
	}

	int Graphics::GetScreenSizeW()
	{
		return (int)((double)(GetSize_a().nWidth) * GetScreenZoomX());
	}

	int Graphics::GetScreenSizeH()
	{
		return (int)((double)(GetSize_a().nHeight) * GetScreenZoomY());
	}

	ThroughType Graphics::GetScreenThrough()
	{
		if(GetThrough_a() != THROUGH_BOTH && m_pgGroup != NULL)
		{
			if(GetThrough_a() == THROUGH_NONE)
				return m_pgGroup->GetScreenThrough();

			else if(m_pgGroup->GetScreenThrough() == THROUGH_NONE)
				return GetThrough_a();

			else if(GetThrough_a() != m_pgGroup->GetScreenThrough())
				return THROUGH_BOTH;

			else
				return GetThrough_a();
		}
		else
			return GetThrough_a();
	}

	Bundle* Graphics::AddInfos()
	{
		return &m_bdlInfo;
	}

	int Graphics::GetGType()
	{
		return m_nGType;
	}

	void Graphics::DockGroup(Graphics* pgGroup)
	{
		if(pgGroup != NULL && m_pgGroup != NULL)
		{
			((Face*)m_pgGroup)->RemoveGraphics(this);
		}

		m_pgGroup = pgGroup;
	}

	Graphics* Graphics::GetDockGroup()
	{
		return m_pgGroup;
	}

	void Graphics::IgnoreSize()
	{
		m_isIgnoreSize = true;
	}

	bool Graphics::IsIgnoreSize()
	{
		return m_isIgnoreSize;
	}

	void Graphics::Associate(AttribType atMaster, Interval& inMaster, AttribType atCharged, Interval& inCharged)
	{
		AttribAssociate _aa;
		_aa.atMaster = atMaster;
		_aa.inMaster = inMaster;
		_aa.atCharged = atCharged;
		_aa.inCharged = inCharged;

 		(m_AllAssociates[atCharged]).push_back(_aa);
	}

	void Graphics::ClearAssociate()
	{
		m_AllAssociates.clear();
	}

	double Graphics::AdjustAssociate(double dCharged, AttribAssociates& aas)
	{
		double _dTotal = 0;
		int _nNum = 0;
		double _dVal = 0;

		for(unsigned int _i = 0; _i < aas.size(); _i++)
		{
			switch(aas[_i].atMaster)
			{
			case ATTRIB_LOCAX:
				if(CalculateAssociate(ATTRIB(Location).nX, dCharged, aas[_i], _dVal))
				{
					_dTotal += _dVal;
					_nNum++;
				}
				break;
			case ATTRIB_LOCAY:
				if(CalculateAssociate(ATTRIB(Location).nY, dCharged, aas[_i], _dVal))
				{
					_dTotal += _dVal;
					_nNum++;
				}
				break;
			}
		}

		if(_nNum <= 0)
			return dCharged;
		else
			return _dTotal / _nNum;
	}

	bool Graphics::CalculateAssociate(double dMaster, double dCharged, AttribAssociate& aa, double& dReturn)
	{
		if(dMaster >= GAF_MATH_MIN(aa.inMaster.dFrom, aa.inMaster.dTo)
			&& dMaster <= GAF_MATH_MAX(aa.inMaster.dFrom, aa.inMaster.dTo))
		{
// 			double _dChargedHowMuch = aa.inCharged.HowMuch();
// 			double _dMasterHowMuch = aa.inMaster.HowMuch();

			dReturn = aa.inCharged.dFrom + 
				aa.inCharged.HowMuch() * 
				(dMaster - aa.inMaster.dFrom) / 
				aa.inMaster.HowMuch() ;
			return true;
		}
		else
		{
// 			if(dMaster < aa.inMaster.dFrom)
// 				return aa.inCharged.dFrom;
// 			else // (dMaster > aa.inMaster.dTo)
// 				return aa.inCharged.dTo;
		}

		return false;
	}
}
